package com.jin.jpa.wrapper;

import com.jin.jpa.wrapper.expression.GroupByExpression;
import com.jin.jpa.wrapper.expression.OrderByExpression;
import com.jin.jpa.wrapper.expression.SelectExpression;

import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Selection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: yuanxiuyao
 * @Date: 2024/1/8 16:28
 * @PackageName: org.example.jpa.wrapper
 * @Version 1.0
 */
public abstract class AbstractWrapper<T> implements AbstractWhereWrapper<T>, AbstractSelectWrapper<T>, AbstractOtherWrapper<T> {

    protected Class<T> instanceClass;

    public AbstractWrapper(Class<T> instanceClass){
        this.instanceClass = instanceClass;
    }

    @Override
    public Class<T> getInstanceClass() {
        return instanceClass;
    }

    protected void multiselect(LambdaWrapperContext<?> lambdaWrapperContext){
        List<Selection<?>> selections = selectExpressions.stream().map(expression -> expression.toHandle(lambdaWrapperContext)).collect(Collectors.toList());
        if(!selections.isEmpty()) lambdaWrapperContext.getCriteriaQuery().multiselect(selections);
    }

    protected void where(LambdaWrapperContext<?> lambdaWrapperContext){
        if(whereOpExpressions.isEmpty()) return;
        Predicate[] predicates = whereOpExpressions.stream().map(expression -> expression.toHandle(lambdaWrapperContext)).toArray(Predicate[]::new);
        if(predicates.length > 0) lambdaWrapperContext.getCriteriaQuery().where(predicates);
    }

    protected void orderBy(LambdaWrapperContext<?> lambdaWrapperContext){
        List<OrderByExpression> orderByExpressions = filterExpression(OrderByExpression.class);
        List<Order> orderList = orderByExpressions.stream().map(expression -> expression.toHandle(lambdaWrapperContext)).collect(Collectors.toList());
        if(!orderList.isEmpty()) lambdaWrapperContext.getCriteriaQuery().orderBy(orderList);
    }

    protected void groupBy(LambdaWrapperContext<?> lambdaWrapperContext){
        List<GroupByExpression> groupByExpressions = filterExpression(GroupByExpression.class);
        List<Expression<?>> expressions = groupByExpressions.stream().map(expression -> expression.toHandle(lambdaWrapperContext)).collect(Collectors.toList());
        if(!expressions.isEmpty()) lambdaWrapperContext.getCriteriaQuery().groupBy(expressions);
    }

}
